/*jslint newcap:true, browser: true, devel: true, bitwise: true, white: true, plusplus: true, forin:true, nomen:true */
/*global define:true */

/**
 * @module Test
 */

define([
	'WID/Test/Matchers/toBe',
	'WID/Test/Matchers/toBeDefined',
	'WID/Test/Matchers/toBeUndefined',
	'WID/Test/Matchers/toBeNull',
	'WID/Test/Matchers/toBeTrue',
	'WID/Test/Matchers/toBeFalse',
	'WID/Test/Matchers/toBeEqual',
	'WID/Test/Matchers/toBeLessThan',
	'WID/Test/Matchers/toBeGreaterThan',
	'WID/Test/Matchers/toBeInstanceOf',
	'WID/Test/Matchers/toBeType',
	'WID/Test/Matchers/toThrow'
],function(
	toBe,toBeDefined,toBeUndefined,toBeNull,
	toBeTrue,toBeFalse,
	toBeEqual,toBeLessThan,toBeGreaterThan,
	toBeInstanceOf,toBeType,toThrow
) {
"use strict";

/** 
 * 
 * @class Matchers
 * @constructor
 */
function Matchers() {
	this.CurrentExpect = -1;
	this.MatchLog = '';
	this.Target = undefined;
	this.Negation = false;
	
	this.loadStdMatchers();
}

Matchers.prototype = {
	constructor: Matchers,
	
	loadStdMatchers: function() {
		this.addMatcher(new toBe());
		this.addMatcher(new toBeDefined());
		this.addMatcher(new toBeUndefined());
		this.addMatcher(new toBeNull());
			
		this.addMatcher(new toBeTrue());
		this.addMatcher(new toBeFalse());
		
		this.addMatcher(new toBeEqual());
		this.addMatcher(new toBeLessThan());
		this.addMatcher(new toBeGreaterThan());
		
		this.addMatcher(new toBeInstanceOf());
		this.addMatcher(new toBeType());
		this.addMatcher(new toThrow());
	},
	
	addMatcher: function(matcher) {
		var context = this;
		this[matcher.getName()] = function (exp) {
			var extra = arguments;
			return context.match(matcher,exp,extra[1]);
		};
	},
	
	match: function(matcher, exp) {
		var 
			extra = arguments,
			matched = matcher.match(this.Target,this.Negation,exp,extra[2]);
		if (!matched) {
			this.logFailure(matcher.getInfo(this.Target,this.Negation,exp,extra[2]));
		} else if (matched === matcher) {
			return matcher; 
		}
	},
	
	newExpect: function(expectIndex, exp) {
		this.CurrentExpect = '<b>('+expectIndex+') Expected</b> ';
		this.Target = exp;
		this.Negation = false;
	},
	
	logFailure: function(log) {
		this.MatchLog = this.CurrentExpect+log;
	}
};

Object.defineProperties(Matchers.prototype,{
	not: {
		get: function() {
			this.Negation = !this.Negation;
			return this;
		}
	},
	
	log: {
		get: function() {
			var l = this.MatchLog;
			this.MatchLog = '';
			return l;
		}
	}
});

return Matchers;
});
